<!-- 上传成功后返回 'url' 或 'url,url' 格式字符串
import useFileDelete from "@/hooks/useFileDelete"
const useDeleteHook = useFileDelete()

可以在关闭弹窗的函数中调用以下函数
// 1 将要删除的文件列表不为空，则删除文件
  await useDeleteHook.deleteFiles()
// 2 清除要删除的文件列表
  useDeleteHook.clearWillDelList()

<image-upload-muti v-model:value="formData.tp" 
v-model:willDelete="useDeleteHook.willDelFiles.value" 
:limit="1" :out-size="60" />

-->
<template>
    <div class="component-upload-image">
        <el-upload :disabled="readonly" multiple :action="uploadImgUrl" :auto-upload="true" list-type="picture-card"
            accept=".bmp, .gif, .jpg, .jpeg, .png, " :on-success="handleUploadSuccess"
            :before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed"
            ref="imageUpload" :before-remove="handleBeforeRemove" :on-remove="handleDelete" :show-file-list="true"
            :headers="headers" :file-list="fileList" :on-preview="handlePictureCardPreview"
            :class="{ hide: fileList.length >= props.limit, ['outSize' + outSize]: true }">
            <el-icon>
                <Plus />
            </el-icon>
        </el-upload>
        <el-dialog v-model="dialogVisible" title="预览" :width="800" append-to-body>
            <el-image @click="preList = [dialogImageUrl]" :preview-src-list="preList" :src="dialogImageUrl"
                fit="contain" style="height: 600px; display:block; margin:0 auto; " />
            <div slot="footer">
                <el-button type="primary" size="small" @click="dialogVisible = false">关闭</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script lang="ts" setup name="ImageUploadMuti">
import { Plus } from '@element-plus/icons-vue'
import { getToken } from '@/utils/auth'
import { ElLoading, ElMessage, ElMessageBox } from "element-plus"
import { computed, ref, watch, getCurrentInstance, type ComponentInternalInstance, onMounted } from 'vue';
interface FileItem {
    modelValue: string | Array<string> | null;
    limit?: number; // 图片数量限制 5
    outSize?: number;//组件大小
    mw?: number;//最小宽度像素
    mh?: number; //最小高度像素,
    whr?: string; //宽高比,
    readonly?: boolean; // 禁用false 
    fileSize?: number;  // 大小限制(MB){ 50
    fileType?: Array<string>; // 文件类型, 例如['png', 'jpg', 'jpeg']{

    willDelete?: Array<string>; //将要删除的文件列表
    uploadPlaceholder?: string; //上传框占位符
}
interface UploadFileItem {
    name: string;
    url: string;
}
const loading = ref()
const props = withDefaults(
    defineProps<FileItem>(), {
    outSize: 98,
    limit: 5,
    modelValue: '',
    readonly: false,
    fileSize: 50,
    fileType: () => ['bmp', 'gif', 'jpg', 'jpeg', 'png',],
    willDelete: () => [],
    uploadPlaceholder: '上传图片',
});
const emit = defineEmits<{
    (e: 'update:modelValue', value: string | undefined): void
    (e: 'update:willDelete', value: Array<string>): void//将要删除的文件列表

}>();

const number = ref(0)
const uploadList = ref([] as UploadFileItem[])
const preList = ref(['#'])
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const baseUrl = import.meta.env.VITE_APP_FILE_API
const uploadImgUrl = '/ddm/upload' // 上传的图片服务器地址
const headers = ref({
    Authorization: 'Bearer ' + getToken()
})
const fileList = ref([] as UploadFileItem[])
const imageUpload = ref()
const { proxy } = getCurrentInstance() as any
// 将要删除的文件
const willDeleteList = ref([] as Array<string>)

// 关闭loading
function closeLoading() {
    if (loading.value) loading.value.close()
}
// 上传前loading加载
async function handleBeforeUpload(file: any) {
    let resBinDataIsImg = await getRealFileType(file)
    let isImg = false
    if (props.fileType.length) {
        let fileExtension = ''
        if (file.name.lastIndexOf('.') > -1) {
            fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
        }
        isImg = props.fileType.some(type => {
            if (file.type.indexOf(type) > -1) return true
            if (fileExtension && fileExtension.indexOf(type) > -1) return true
            return false
        })
    } else {
        isImg = file.type.indexOf('image') > -1
    }

    if (!resBinDataIsImg) {
        ElMessage.error(`文件后缀名被修改或文件已损坏`)
        return Promise.reject()
    }
    if (!isImg) {
        ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`)
        // _removeFile(file)
        return Promise.reject()
    }
    if (props.fileSize) {
        const isLt = file.size / 1024 / 1024 < props.fileSize
        if (!isLt) {
            ElMessage.error(`上传图片大小不能超过 ${props.fileSize} MB!`)
            // _removeFile(file)
            return Promise.reject()
        }
    }
    loading.value = ElLoading.service({
        lock: true,
        text: '正在上传...',
        background: 'rgba(0, 0, 0, 0.7)'
    })
    number.value++
}


/**
* 根据文件内容判断文件的真实类型
*
* @param file File 文件对象
* @returns 返回一个 Promise，resolve 参数为布尔值，表示文件是否为图片文件
*/
function getRealFileType(file: any) {
    return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = (e: any) => {
            const arr = new Uint8Array(e.target.result).subarray(0, 2);
            let header = '';
            for (let i = 0; i < arr.length; i++) {
                header += arr[i].toString(16);
            }
            let realType = '';
            switch (header.toLowerCase()) {
                case '8950': realType = 'png'; break;
                case '4749': realType = 'gif'; break;
                case 'ffd8': realType = 'jpg'; break;
                case '424d': realType = 'bmp'; break;
                default: realType = 'unknown';
            }
            if (realType && realType != 'unknown') {
                resolve(true)
            } else {
                resolve(false)
            }
        };
        reader.readAsArrayBuffer(file);
    });
}

// 文件个数超出
function handleExceed() {
    ElMessage.error(`上传文件数量不能超过 ${props.limit} 个!`)
}
// 上传成功回调
function handleUploadSuccess(res: any, file: any) {
    if (res.status == 0) {
        uploadList.value.push({
            name: res.data.name,
            url: res.data.value,
        })
        uploadedSuccessfully()
    } else {
        number.value--
        closeLoading()
        ElMessage.error(res.msg)
        file.status = 'fail'
        removeFile(file)
        uploadedSuccessfully()
    }
}
function removeFile(file: any) {
    imageUpload.value.handleRemove(file)
}
// 删除图片前
async function handleBeforeRemove(file: any, fileList: any) {
    if (file && file.status != 'success') {
        closeLoading()
        // 不符合条件的图片删除
        let indext = -1
        fileList.forEach((item: any, index: number) => {
            if (item.name == file.name) {
                indext = index
            }
        })

        // imageUpload.value.uploadFiles.splice(indext, 1)
        return fileList
    } else if (file && file.status == 'success') {
        return ElMessageBox.confirm('确认删除此文件？', "提示",)
    }
}

// 删除图片
async function handleDelete(file: any) {
    if (file) {
        willDeleteList.value.push(file.name)
        emit('update:willDelete', willDeleteList.value)
        let findex = fileList.value.map(f => f.name).indexOf(file.name)
        if (findex > -1) {
            fileList.value.splice(findex, 1)
            emit('update:modelValue', listToString(fileList.value, null))
        }
    }
}
// 上传失败
function handleUploadError() {
    ElMessage.error('上传图片失败，请重试')
    closeLoading()
}
// 上传结束处理
function uploadedSuccessfully() {
    if (number.value > 0 && uploadList.value.length === number.value) {
        fileList.value = fileList.value.concat(uploadList.value)
        uploadList.value = []
        number.value = 0
        emit('update:modelValue', listToString(fileList.value, null))
        closeLoading()
    }
}
// 预览
function handlePictureCardPreview(file: any) {
    dialogImageUrl.value = file.url
    dialogVisible.value = true
}
// 对象转成指定字符串分隔
function listToString(list: any, separator: any) {
    let strs = ''
    separator = separator || import.meta.env.VITE_FILE_URL_SEPARATOR

    for (let i in list) {
        if (list[i].url) {
            strs += list[i].url.replace(baseUrl, '') + separator
        }
    }
    return strs != '' ? strs.substr(0, strs.length - import.meta.env.VITE_FILE_URL_SEPARATOR.length) : ''
}

// 监听value的变化

watch(() => props.modelValue, (val: any) => {
    if (val && (Array.isArray(val) || typeof val === 'string')) {
        // 首先将值转为数组
        let list: Array<string> = []
        if (Array.isArray(val)) {
            list = val
        } else {
            list = (props.modelValue as string).split(import.meta.env.VITE_FILE_URL_SEPARATOR)
        }
        // 然后将数组转为对象数组
        fileList.value = list.map(item => {
            if (typeof item === 'string') {
                item = { name: item, url: item } as any
            }
            return item as any
        })
    } else {
        fileList.value = []
        return []
    }
}, {
    deep: true,
    immediate: true
})
watch(() => props.willDelete, (n) => {
    willDeleteList.value = n
}, {
    immediate: true,
    deep: true,
})

// 监听窗口大小变化，重新计算对话框宽度

</script>

<style lang="scss" scoped>
@use "sass:math";

//动态创建css
@for $i from 1 through 100 {
    :deep(.outSize#{$i}) {
        .el-upload--picture-card {
            width: $i * 1px !important;
            height: $i * 1px !important;
            line-height: ($i * 1.3) * 1px;

            img {
                top: calc(50% - 20px);
            }
        }

        .el-upload-list__item {
            width: $i * 1px !important;
            height: $i * 1px !important;
        }

        .el-upload-list__item-preview {
            position: absolute;
            left: (math.div($i, 4) - 10) * 1px !important;
            top: (math.div($i, 2) - 10) * 1px !important;
        }

        .el-upload-list__item-delete {
            position: absolute;
            margin-left: 0;
            left: (math.div($i, 4) * 3-10) * 1px !important;
            top: (math.div($i, 2)-10) * 1px !important;
        }
    }
}

.upload-default-icon {
    line-height: 26px;
    display: flex;
    text-align: center;
    justify-content: center;
    flex-direction: column;
    align-items: center;

    img {
        display: block;
        width: 20px;
        height: 20px;
    }
}

// .el-upload--picture-card 控制加号部分
.hide :deep(.el-upload--picture-card) {
    display: none;
}

:deep(.el-image__preview) {
    cursor: zoom-in;
    width: 100%;
    margin: 0 auto;
    display: block;
}

:deep(.el-upload--picture-card) {
    width: 100px;
    height: 100px;
    position: relative;
}

:deep(.el-upload--picture-card i) {
    position: absolute;
    top: 35px;
    left: 0;
    right: 0;
    margin: 0 auto;
}

:deep(.el-upload-list--picture-card .el-upload-list__item) {
    width: 100px;
    height: 100px;
    transition: unset;
    -webkit-transition: unset;
}

:deep(.el-progress-circle) {
    width: 100px !important;
    height: 100px !important;
    padding-left: 26px;
    padding-top: 10px;
}

// 去掉动画效果
:deep(.el-list-enter-active),
:deep(.el-list-leave-active) {
    transition: all 0s;
}

:deep(.el-list-enter),
:deep(.el-list-leave-active) {
    opacity: 0;
    transform: translateY(0);
}

.sortable-item {
    transition: transform 150ms ease-in-out;
}
</style>
